package cn.airfei.aircore.core.interceptor;

import cn.airfei.aircore.core.extend.InsertLogToMongoDb;
import cn.airfei.aircore.core.extend.ParseHeaderAuthorization;
import cn.airfei.aircore.core.properties.AirCoreProperty;
import cn.airfei.aircore.core.storage.Pojo.LogForMongoDbPojo;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.time.LocalDateTime;

/**
 * @description: RestTemplate拦截器
 * @author: air
 * @create: 2020-11-12 09:43
 */
@Slf4j
@Component
public class RestTemplateInterceptor implements ClientHttpRequestInterceptor {
    @Resource
    private AirCoreProperty airCoreProperty;

    @Resource
    private InsertLogToMongoDb insertLogToMongoDb;

    @Resource
    private ParseHeaderAuthorization parseHeaderAuthorization;

    @Override
    public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
        traceRequest(request, body);
        ClientHttpResponse response = execution.execute(request, body);
        traceResponse(response, request);
        return response;
    }

    private void traceRequest(HttpRequest request, byte[] body) throws IOException {
        log.info("=========================== restTemplate request begin ================================================");
        log.info("URI         : {}", request.getURI());
        log.info("Method      : {}", request.getMethod());
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (attributes != null) {
            HttpServletRequest httpServletRequest = attributes.getRequest();
            httpServletRequest.setAttribute("restTemplateUrl", request.getURI());
            String traceId = String.valueOf(httpServletRequest.getAttribute("traceId"));
            request.getHeaders().set("traceId", traceId);
            request.getHeaders().set("requestId", IdWorker.get32UUID());
            if (request.getHeaders().get("Authorization") == null && !StringUtils.isEmpty(httpServletRequest.getHeader("Authorization"))) {
                request.getHeaders().set("Authorization", httpServletRequest.getHeader("Authorization"));
            }
            if (request.getHeaders().get("token") == null && !StringUtils.isEmpty(httpServletRequest.getHeader("token"))) {
                request.getHeaders().set("token", httpServletRequest.getHeader("token"));
            }
            if (request.getHeaders().get("requestMark") == null && !StringUtils.isEmpty(httpServletRequest.getHeader("requestMark"))) {
                request.getHeaders().set("requestMark", httpServletRequest.getHeader("requestMark"));
            } else {
                request.getHeaders().set("requestMark", "restTemplate");
            }
            log.info("Headers     : {}", request.getHeaders());
            log.info("Request body: {}", new String(body, "UTF-8"));
            // 写入日志到mongoDb
            if (airCoreProperty.getSetLogToMongoDb()) {
                LogForMongoDbPojo logForMongoDbPojo = new LogForMongoDbPojo();
                logForMongoDbPojo.setCreateTime(LocalDateTime.now());
                logForMongoDbPojo.setUrl(String.valueOf(request.getURI()));
                logForMongoDbPojo.setTraceId(traceId);
                logForMongoDbPojo.setRequestId(request.getHeaders().getFirst("requestId"));
                logForMongoDbPojo.setMethod(String.valueOf(request.getMethod()));
                logForMongoDbPojo.setParams(new String(body, "UTF-8"));
                logForMongoDbPojo.setRemark("restTemplate request");
                logForMongoDbPojo.setToken(httpServletRequest.getHeader("token"));
                logForMongoDbPojo.setAuthorization(httpServletRequest.getHeader("Authorization"));
                logForMongoDbPojo.setHeaders(String.valueOf(request.getHeaders()));
                parseHeaderAuthorization.setLoginInfo(logForMongoDbPojo);
                insertLogToMongoDb.insertLog(logForMongoDbPojo);
            }
        }
        log.info("============================ restTemplate request end ================================================");
    }

    private void traceResponse(ClientHttpResponse response, HttpRequest request) throws IOException {
        StringBuilder inputStringBuilder = new StringBuilder();
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(response.getBody(), "UTF-8"));
        String line = bufferedReader.readLine();
        while (line != null) {
            inputStringBuilder.append(line);
            inputStringBuilder.append('\n');
            line = bufferedReader.readLine();
        }
        log.info("============================ restTemplate response begin ================================================");
        log.info("Status code  : {}", response.getStatusCode());
        log.info("Status text  : {}", response.getStatusText());
        log.info("Headers      : {}", response.getHeaders());
        log.info("Response body: {}", inputStringBuilder.toString());

        // 写入日志到mongoDb
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (attributes != null) {
            if (airCoreProperty.getSetLogToMongoDb()) {
                HttpServletRequest httpServletRequest = attributes.getRequest();
                String traceId = String.valueOf(httpServletRequest.getAttribute("traceId"));
                LogForMongoDbPojo logForMongoDbPojo = new LogForMongoDbPojo();
                logForMongoDbPojo.setCreateTime(LocalDateTime.now());
                logForMongoDbPojo.setUrl(String.valueOf(request.getURI()));
                logForMongoDbPojo.setTraceId(traceId);
                logForMongoDbPojo.setRequestId(request.getHeaders().getFirst("requestId"));
                logForMongoDbPojo.setMethod(String.valueOf(request.getMethod()));
                logForMongoDbPojo.setResult(inputStringBuilder.toString());
                logForMongoDbPojo.setRemark("restTemplate result");
                logForMongoDbPojo.setCode(String.valueOf(response.getStatusCode()));
                logForMongoDbPojo.setHeaders(String.valueOf(response.getHeaders()));
                parseHeaderAuthorization.setLoginInfo(logForMongoDbPojo);
                insertLogToMongoDb.insertLog(logForMongoDbPojo);
            }
        }
        log.info("============================ restTemplate response end =================================================");
    }


}